package lib

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"

	"github.com/gin-gonic/gin"
	"gopkg.in/go-playground/validator.v9"
)

/*------------------------------------------------------------------------------
=====================================Handler====================================
------------------------------------------------------------------------------*/
type IService interface {
	Handle(c *gin.Context) Response_
}

func Service(c *gin.Context, s IService) {
	/*
			fmt.Println("---QSubmit header:/--- ")
			for k, v := range c.Request.Header {
				fmt.Println(k, v)
			}
			body, _ := ioutil.ReadAll(c.Request.Body)
			fmt.Println("---body/---\n " + string(body))

		c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
	*/
	if err := c.ShouldBind(s); err == nil {
		c.JSON(200, logRespErr(c, s.Handle(c)))
	} else {
		c.JSON(200, logRespErr(c, RespValidErr(err)))
	}
}

// ------------
func logRespErr(c *gin.Context, r Response_) Response_ {
	if r.Err() != nil {
		strs := make([]string, 0, len(r.errs)-1)
		for i := len(r.errs) - 1; i > 0; i-- {
			strs = append(strs, r.errs[i].Error())
		}
		fmt.Printf("[\"HTP-Resp-Err\"]%s %s -> {code:%v msg:%q err:%v}\n", c.Request.RequestURI, strings.Join(strs, " -> "), r.Code, r.Msg, r.errs[0])
	}
	return r
}

/*------------------------------------------------------------------------------
====================================Response_====================================
------------------------------------------------------------------------------*/

// => 错误码定义[3位数:复用http原本语义]
const (
	CodeSucessed     = 0    // http.StatusOK
	CodeNotLogin     = 401  // 未登录
	CodeNoRight      = 403  // 未授权访问
	CodeDBError      = 1001 // 数据库错误
	CodeEncrypt      = 1002 // 加密解密错误
	CodeParamErr     = 1003 // 参数错误
	CodeAuthStamp    = 1010 // 时间戳错误
	CodeAuthHash     = 1011 // Hash错误
	CodeAuthFaild    = 1012 // 认证错误
	CodeTokenNil     = 1013 // Head中没有携带token
	CodeTokenExpired = 1014 // token过期
	CodeTokenErr     = 1015 // token错误
	CodeTokenMake    = 1016 // token生成
)

// Response_ 基础序列化器
type Response_ struct {
	Code  int         `json:"err"`
	Data  interface{} `json:"data,omitempty"`
	Msg   string      `json:"msg"`
	Error string      `json:"errs,omitempty"`

	errs []error // 程序内部使用
}

func (r *Response_) Err() error {
	if r.Code == CodeSucessed {
		return nil
	}
	if r.errs[0] == nil {
		return fmt.Errorf("Code=%d", r.Code)
	}
	return r.errs[0]
}
func (r *Response_) Track(s string) Response_ {
	if r.Err() != nil {
		r.errs = append(r.errs, errors.New(s))
	}
	return *r
}

// 成功返回
func RespOK(msg string, data interface{}) Response_ {
	if msg == "" {
		msg = "🆗"
	}
	return Response_{Code: CodeSucessed, Data: data, Msg: msg}
}

// 通用错误处理
func RespErr(errCode int, msg string, err error) Response_ {
	res := Response_{
		Code: errCode,
		Msg:  msg,
	}
	res.errs = append(res.errs, err)
	if err != nil && gin.Mode() != gin.ReleaseMode {
		res.Error = err.Error()
	}
	return res
}

// 数据库操作失败
func RespDBErr(msg string, err error) Response_ {
	if msg == "" {
		msg = "数据库操作失败"
	}
	return RespErr(CodeDBError, msg, err)
}

// 各种参数错误
func RespParamErr(msg string, err error) Response_ {
	if msg == "" {
		msg = "参数错误"
	}
	return RespErr(CodeParamErr, msg, err)
}

// 校验器返回错误
func RespValidErr(err error) Response_ {
	if ve, ok := err.(validator.ValidationErrors); ok {
		for _, e := range ve {
			field := fmt.Sprintf("Field.%s", e.Field())
			tag := fmt.Sprintf("Tag.Valid.%s", e.Tag())
			return RespParamErr(fmt.Sprintf("%s%s", field, tag), err)
		}
	}
	if _, ok := err.(*json.UnmarshalTypeError); ok {
		return RespParamErr("JSON类型不匹配", err)
	}

	return RespParamErr("参数错误", err)
}
